//
//  YDCycleScrollView.swift
//  YDCycleScrollView
//
//  Created by alyadan on 2017/3/13.
//  Copyright © 2017年 alyadan. All rights reserved.
//

import Foundation
import MVVM_BaseViewController
import SnapKit
import RxSwift
import RxCocoa
import YD_Util

public class YD_CustomScrollView: UIScrollView, UIGestureRecognizerDelegate {
    
    public var gestureShouldBeginBlock: ((UIScrollView, UIGestureRecognizer) -> Bool)?
    
    var contentView = UIView()
    
    public override init(frame: CGRect) {
        super.init(frame: frame)
        self.addSubview(contentView)
    }
    
    
    required public init?(coder aDecoder: NSCoder) {
        fatalError("init(coder:) has not been implemented")
    }
    
    public override func gestureRecognizerShouldBegin(_ gestureRecognizer: UIGestureRecognizer) -> Bool {
        
        if let ges = gestureRecognizer as? UIPanGestureRecognizer {
            if self.contentOffset.x == 0 && ges.velocity(in: ges.view).x > 0 {
                return false
            } else if self.contentOffset.x >= (contentSize.width - UIScreen.main.bounds.width) && ges.velocity(in: ges.view).x < 0 {
                return false
            }
            
        }
        
        return self.gestureShouldBeginBlock?(self, gestureRecognizer) ?? true
    }
    
}

public class YDCycleScrollView: UIView ,UIScrollViewDelegate{
    
    override public var currentModel: YDCycleScrollViewModel {
        return viewModel.value as! YDCycleScrollViewModel
    }
    
    public let scrollView: YD_CustomScrollView = {
        let x = YD_CustomScrollView()
        x.isPagingEnabled = true
        x.bounces = false
        x.scrollsToTop = false
        //        x.showsHorizontalScrollIndicator = false
        //        x.showsHorizontalScrollIndicator = false
        return x
    }()
    
    public let pageControll: UIPageControl = {
        let x = UIPageControl()
        return x
    }()
    
    override public func setupUI() {
        self.addSubview(self.scrollView)
        self.scrollView.delegate = self
        
        scrollSetupUI()
        self.addSubview(pageControll)
        pageControll.isHidden = !currentModel.showPageController
        
    }
    
    open func scrollSetupUI() {
        
        self.pageControll.numberOfPages = currentModel.yd_contentViews.count
        for aView in currentModel.yd_contentViews {
            completeAddSubview(view: aView, parentView: self.scrollView.contentView)
            
            findScrollView(parentView: aView)?.scrollsToTop = false
        }
        
        if currentModel.shouldControllScrollToTop {
            setScrollToTop(index: currentModel.pageIndex.value)
        }
        
    }
    
    func completeAddSubview(view: UIView, parentView: UIView) {
        if view.superview != nil, view.superview == parentView {
            return
        }
        
        if let vc = view.next as? UIViewController, let parentVc = self.currentModel.MVVM_modelController {
            parentVc.addChild(vc)
            vc.didMove(toParent: parentVc)
        }
        parentView.addSubview(view)
    }
    
    func completeRemoveView(view: UIView) {
        if let vc = view.next as? UIViewController {
            vc.willMove(toParent: nil)
            vc.removeFromParent()
        }
        
        view.removeFromSuperview()
        
    }
    
    
    var initFlag = false
    
    override public func layoutSubviews() {
        super.layoutSubviews()
        self.scrollView.snp.updateConstraints { (ConstraintMaker) in
            ConstraintMaker.edges.equalTo(UIEdgeInsets.zero)
        }
        
        self.pageControll.snp.updateConstraints {[unowned self] (ConstraintMaker) in
            ConstraintMaker.centerX.equalTo(self)
            ConstraintMaker.bottom.equalTo(self.scrollView.snp.bottom)
        }
        
        scrollLayoutSubViews()
    }
    
    func scrollLayoutSubViews() {
        
        self.scrollView.contentView.snp.remakeConstraints {[unowned self] (ConstraintMaker) in
            ConstraintMaker.top.left.bottom.right.equalTo(self.scrollView)
            ConstraintMaker.height.equalTo(self.scrollView)
            ConstraintMaker.width.equalTo(self.scrollView).multipliedBy(self.currentModel.yd_contentViews.count)
        }
        
        var lastView: UIView?
        
        if self.scrollView.contentView.subviews.count == 0 {
            scrollSetupUI()
        }
        
        for (_, aView) in currentModel.yd_contentViews.enumerated() {
            
            aView.snp.remakeConstraints({[unowned self] (ConstraintMaker) in
                
                //                ConstraintMaker.centerY.equalTo(self.scrollView.contentView)
                ConstraintMaker.top.equalTo(self.scrollView)
                ConstraintMaker.height.equalTo(self.scrollView)
                ConstraintMaker.width.equalTo(self.scrollView)
                
                if let x = lastView {
                    ConstraintMaker.left.equalTo(x.snp.right)
                } else {
                    ConstraintMaker.left.equalTo(self.scrollView.contentView)
                }
                
            })
            
            lastView = aView
        }
        
        self.scrollView.contentSize = CGSize(width: CGFloat(currentModel.yd_contentViews.count) * self.frame.width, height: self.frame.height)
        
        
        if !initFlag {
            self.scrollView.setContentOffset(CGPoint.init(x: CGFloat(currentModel.pageIndex.value) * self.frame.width, y: 0), animated: false)
            initFlag = true
        }
        
    }
    
    func findScrollView(parentView: UIView) -> UIScrollView? {
        if parentView.isKind(of: UIScrollView.self) {
            return parentView as? UIScrollView
        }
        
        for v in parentView.subviews {
            if v.isKind(of: UIScrollView.self) {
                return v as? UIScrollView
            }
        }
        
        for v in parentView.subviews {
            return findScrollView(parentView: v)
        }
        
        
        return nil
    }
    
    
    func setScrollToTop(index: Int) {
        if self.currentModel.yd_contentViews.count == 0 {
            return
        }
        
        let destView = self.currentModel.yd_contentViews[index]
        if let v = currentContentView {
            findScrollView(parentView: v)?.scrollsToTop = false
        }
        currentContentView = destView
        if let scrollView = self.findScrollView(parentView: destView) {
            scrollView.scrollsToTop = true
        }
    }
    
    
    private var currentContentView: UIView?
    public override func bindModelData() {
        currentModel.pageIndex.asDriver()
            .drive(onNext:
                {[unowned self] (index: Int) in
                    //            self.pageControll.currentPage = index
                    
                    guard self.frame.width != 0 else{
                        return
                    }
                    
                    let pageIndex = Int(self.scrollView.contentOffset.x / self.frame.width)
                    if index != pageIndex {
                        self.scrollView.scrollRectToVisible(self.getRect(pageIndex: index), animated: true)
                    }
                    
                    self.setScrollToTop(index: index)
                    
                }, onCompleted: nil, onDisposed: nil)
            .addDisposableTo(disposeBag)
        
        currentModel.pageControlIndex.asDriver()
            .drive(self.pageControll.rx.currentPage)
            .addDisposableTo(disposeBag)
        
        if currentModel.timerInterval != 0 {
            
            var dispose: Disposable?
            dispose = Observable<Int>.interval(currentModel.timerInterval, scheduler: MainScheduler.instance)
                .asDriver(onErrorJustReturn: 0)
                .drive(onNext: {[unowned self] _ in
                    let nextIndex = self.currentModel.pageIndex.value + 1
                    if nextIndex > self.currentModel.yd_contentViews.count - 1 {
                        dispose?.dispose()
                        return
                    }
                    
                    self.currentModel.pageIndex.value = nextIndex
                    //                    self.scrollView.setContentOffset(CGPoint.init(x: self.frame.width * 2, y: 0), animated: true)
                })
            
            dispose?.addDisposableTo(disposeBag)
            
        }
        
        currentModel.reloadBlock = {[unowned self] in
            self.scrollSetupUI()
            self.setNeedsLayout()
        }
        
    }
    
    func getRect(pageIndex: Int) -> CGRect {
        return CGRect(x: CGFloat(pageIndex) * self.frame.width, y: 0, width: self.frame.width, height: self.frame.height)
    }
    
    public func scrollViewDidScroll(_ scrollView: UIScrollView) {
        
        guard self.frame.width != 0 else{
            return
        }
        
        let pageIndex = Int(scrollView.contentOffset.x / self.frame.width)
        
        if pageIndex != currentModel.pageIndex.value {
            currentModel.pageIndex.value = pageIndex
        }
        
        //        print("111-----\(scrollView.contentOffset.x)")
    }
    
    public func scrollViewDidEndScrollingAnimation(_ scrollView: UIScrollView) {
        guard self.frame.width != 0 else{
            return
        }
        
        currentModel.pageControlIndex.value = Int(self.scrollView.contentOffset.x / self.frame.width)
    }
    
    //    public func scrollViewWillBeginDragging(_ scrollView: UIScrollView) {
    //        print("333-----\(scrollView.contentOffset.x)")
    //    }
    //
    //
    //    public func scrollViewDidEndDragging(_ scrollView: UIScrollView, willDecelerate decelerate: Bool) {
    //        print("444-----\(scrollView.contentOffset.x)")
    //    }
    
    public func scrollViewDidEndDecelerating(_ scrollView: UIScrollView) {
        
        guard self.frame.width != 0 else{
            return
        }
        
        currentModel.pageControlIndex.value = Int(self.scrollView.contentOffset.x / self.frame.width)
    }
    
}

public class YDCycleScrollViewModel: MVVM_BaseViewModel {
    
    public var shouldControllScrollToTop = true
    
    public var yd_contentViews = [UIView]()
    
    public var showPageController = false
    
    public var reloadBlock: (() -> Void)?
    
    /// 真实ViewIndex
    public var pageIndex: Variable<Int>!
    
    
    /// 最终显示对应页面index
    public var pageControlIndex: Variable<Int>!
    
    /*
     * for cycleScrollView
     */
    
    
    /// 轮播时长 如果为0则不轮播
    public var timerInterval:Double = 0
    
    /// 是否为循环
    public let canCycle: Bool
    
    /// 实际中间位置对应页面index
    /// - 根据这个属性来调整页面位置
    public var cyclePageIndex: Variable<Int>!
    
    public init(parentViewModel: MVVM_BaseViewModel?, startIndex: Int = 0, canCycle: Bool = false) {
        self.canCycle = canCycle
        
        self.pageIndex = Variable<Int>(canCycle ? 1 : startIndex)
        
        self.cyclePageIndex = Variable<Int>(startIndex)
        self.pageControlIndex = Variable<Int>(startIndex)
        super.init(parentViewModel: parentViewModel)
    }
    
    override public func setupModel() {
        
    }
}

